import {
  Component,
  OnInit,
  ViewEncapsulation,
  ChangeDetectionStrategy,
  Input,
  Output,
  EventEmitter,
  Pipe,
  PipeTransform,
  ViewChild,
  OnChanges,
  SimpleChanges,
  ViewChildren,
  ChangeDetectorRef,
} from '@angular/core';
import { filter as _filter, isNil as _isNil } from 'lodash';
import { FilterConfig, InputBoolean, InputNumber, LvSizeLSD, TypeUtils } from '../core/api';
import { DatatableComponent } from '../datatable/api';
import { PaginatorComponent } from '../pagination/api';
import { TransferBelong, FilterType, TransferColumnItem } from './transfer.interface';
import { TransferService } from './transfer.service';

@Pipe({ name: 'selectable' })
export class SelectionPipe implements PipeTransform {
  /**
   *
   * @param value 源数据
   * @param exponent 过滤属性
   */
  transform(value: any[], exponent: string = 'disabled'): any {
    return _filter(value, (item): boolean => !item[exponent]);
  }
}

/**
 * 空白显示配置
 * 数据为null或undefined或‘’时，显示空白
 * showZero 特殊场景：0也显示空白
 */
@Pipe({ name: 'nil' })
export class NilPipe implements PipeTransform {
  constructor() {}

  transform(value: any, showZero: boolean = true): any {
    return (_isNil(value) || value === '') && (showZero || value === 0) ? '--' : value;
  }
}

@Component({
  selector: 'lv-transfer-table',
  templateUrl: './transfer-table.component.html',
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: {
    class: 'lv-transfer-table',
  },
})
export class TransferTableComponent implements OnInit, OnChanges {
  @Input() lvData: any[]; // 数据

  @Input() lvDataKey: string; // 唯一标识，用于data被选中的比较，默认为id

  @Input() @InputBoolean() lvAsync;

  @Input() @InputNumber() lvPageSize = 5;

  @Input() lvSize: LvSizeLSD = 'default'; // size

  @Input() lvColumns: TransferColumnItem[];

  @Input() lvPaginator: PaginatorComponent; // 关联分页组件

  @Input() @InputBoolean() lvShowFilter = true;

  @Input() lvBelong: TransferBelong = 'source';

  @ViewChildren('filterPopover') filterPopover;

  @Input() @InputBoolean() lvShowColControl = true; // 是否显示列显示隐藏配置

  @Input() lvSelection: Array<{ [key: string]: any }> = [];

  @Output() lvRemoveItem = new EventEmitter<{ [key: string]: any }>();

  @Output() lvStateChange = new EventEmitter<{ [key: string]: any }>();

  @Output() lvSelectionChange = new EventEmitter<Array<{ [key: string]: any }>>();

  @ViewChild(DatatableComponent, { static: true }) lvTable: DatatableComponent;

  @Output() colDisplayChange = new EventEmitter<{
    currentCol: TransferColumnItem;
    displayCols: TransferColumnItem[];
  }>();

  pageSize: number;
  _parentComponent;

  pageIndex: number;
  isAutoMove: boolean;

  typeUtils = TypeUtils;
  belong: TransferBelong;
  filterType = FilterType;
  currentSearchKey: string; // 当前激活输入框的列
  columns: TransferColumnItem[] = [];
  selection: Array<{ [key: string]: any }>;
  params: { [key: string]: any } = {}; // 所有搜索条件

  currentFilterCol: TransferColumnItem;
  filterParam: { [key: string]: any } = {}; // 列搜索参数

  constructor(
    private service: TransferService,
    private cdr: ChangeDetectorRef,
  ) {
    this._parentComponent = this.service.getParentComponent();
  }

  _beforeClose = (): void => {
    // 清除
    this.filterParam = {};
  };

  _beforeOpen =
    (col: TransferColumnItem): (() => void) =>
    (): void => {
      this.currentSearchKey = col.key;
      this.currentFilterCol = col;
      // 回显
      this.filterParam[this.currentSearchKey] = this.params?.filters?.[this.currentSearchKey] ?? '';
    };

  /**
   * ngFor遍历的 trackBy函数，防止数据更新导致所有DOM重新渲染
   */
  trackByIndex(index): any {
    return index;
  }

  removeItem(data): void {
    this.lvRemoveItem.emit(data);
  }

  selectionChange(selection): void {
    this.lvSelectionChange.emit(selection);
  }

  _initPage(): void {
    this.pageSize = this.lvPageSize;
    this.pageIndex = 0;
  }

  _resetDate(): void {
    this.filterParam[this.currentSearchKey] = null;
    this._selectDate();
  }

  filterChange(config: FilterConfig): void {
    this.lvTable.filter(config);
    this.lvPaginator.jumpToFisrtPage();
  }

  _selectDate(): void {
    this._search(this.filterParam[this.currentSearchKey], 'date');
    this.filterPopover.toArray().forEach((o): any => o.hide());
  }

  _isNullDate(): boolean {
    const date = this.filterParam[this.currentSearchKey] || [null, null];
    return !date?.length || date[0] === null || date[1] === null;
  }

  toggleSelect(source): void {
    if (source.disabled || !(this.belong === 'source' || !this.isAutoMove)) {
      return;
    }
    this.lvTable.toggleSelection(source);
  }

  ngOnInit(): void {
    this.isAutoMove = !this._parentComponent?.lvShowOperation;

    this.columns = this.lvColumns ?? [];
    this.selection = this.lvSelection ?? [];

    this._initPage();
  }

  getRowCursor(source): 'not-allowed' | 'pointer' | string {
    if (!(this.belong === 'source' || !this.isAutoMove)) {
      return 'default';
    } else {
      return source.disabled ? 'not-allowed' : 'pointer';
    }
  }

  _search(value, type?): void {
    const filterMode = type === 'date' ? 'timeIn' : 'contains';
    this.lvTable.filter({
      key: this.currentSearchKey,
      value,
      filterMode: this.currentFilterCol.filterMode || filterMode,
    });
  }

  /**
   * 列配置
   */
  _toggleCols(e, data): void {
    e.stopPropagation();
    // disabled 不可操作
    if (data.disabled) {
      return;
    }
    Promise.resolve().then((): void => {
      data.isHidden = !data.isHidden;
      this.colDisplayChange.emit({ currentCol: data, displayCols: this.getShowCols(this.columns) });
    });
  }

  /**
   * 更新参数
   */
  _updateParams(e: { [key: string]: any } = {}): void {
    // 获取分页器和排序默认初始化值
    const getDefaultParams = (): { paginator: { pageIndex: number; pageSize: number } } => ({
      paginator: { pageIndex: this.pageIndex, pageSize: this.pageSize },
    }); // 默认把分页器参数带上

    this.params = { ...getDefaultParams(), ...this.params, ...e };

    this.lvStateChange.emit(this.params);
  }

  /**
   * 所有条件变更时
   * @param source 条件
   */
  stateChange({ paginator, filterState, sort }): void {
    const params: { [key: string]: any } = {};

    // NEED_DO
    if (paginator) {
      params.paginator = paginator;
    }

    if (filterState) {
      params.filters = {};
      filterState.forEach((o: any): void => {
        const { key, value } = o;
        params.filters[key] = value;
      });
    }

    // NEED_DO
    if (sort) {
      const { key, direction } = sort;
      params.sort = { key, direction };
    }

    this._updateParams(params);
  }

  ngOnChanges(changes: SimpleChanges): void {
    const { lvColumns: columnsChange, lvSelection: selectionChange, lvBelong: belongChange } = changes;

    if (columnsChange && !columnsChange.firstChange) {
      // 非初始化，列变更时应清空表格所有过滤项并跳转到第一页
      this.lvTable.removeFilter();
      this.lvTable.removePage();
      this.lvTable.removeSort();
      this.lvPaginator.jumpToFisrtPage();

      this.columns = columnsChange.currentValue ?? [];
      this.selection = this.lvSelection ?? [];
    }

    selectionChange && (this.selection = selectionChange.currentValue ?? []);

    if (belongChange) {
      this.belong = this.lvBelong ?? 'source';
    }

    this.cdr.markForCheck();
  }

  private getShowCols(cols: TransferColumnItem[]): TransferColumnItem[] {
    return _filter(cols, (o): boolean => !o.isHidden);
  }
}
